package com.acme.superlogger.slf4j;

import org.slf4j.ILoggerFactory;
import org.slf4j.Logger;
import org.slf4j.helpers.Util;

import java.io.*;
import java.util.Properties;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;

public class LoggerFactory implements ILoggerFactory {


    private final String format;

    private final Level threshold;

    private ConcurrentMap<String, Logger> loggerMap;

    private final AsyncWriter writer;

    public LoggerFactory() {
        loggerMap = new ConcurrentHashMap<String, Logger>();
        Properties conf = new Properties();
        Properties sysProperties = System.getProperties();
        try {
            if (sysProperties.containsKey("superlogger.conf")) {
                File file = new File(sysProperties.getProperty("superlogger.conf"));
                conf.load(new FileInputStream(file));
            } else {
                Util.report("Configuration file not specified!");
            }
        } catch (IOException e) {
            Util.report("Couldn't open config file!");
        }
        format = initFormat(conf);
        threshold = initThreshold(conf);
        writer = new AsyncWriter(initOut(conf));
    }

    private Level initThreshold(Properties conf) {
        Level threshold = null;

        // superlogger.threshold
        if (conf.containsKey("superlogger.threshold")) {
            try {
                threshold = Level.valueOf(conf.getProperty("superlogger.threshold").toUpperCase());
            } catch (NullPointerException | IllegalArgumentException e) {
                Util.report("superlogger.threshold parameter is incorrect");
                threshold = null;
            }
        }

        if (threshold == null) {
            threshold = Level.DEBUG;
            Util.report("Using default threshold: " + threshold);
        }
        return threshold;
    }

    private PrintWriter initOut(Properties conf) {
        PrintWriter out = null;

        String output = conf.getProperty("superlogger.output", "console");
        if ("file".equals(output)) {
            // superlogger.file
            if (conf.containsKey("superlogger.file")) {
                try {
                    out = new PrintWriter(new FileOutputStream(conf.getProperty("superlogger.file")));
                } catch (IOException e) {
                    Util.report("Couldn't open log file for output!");
                    out = null;
                }
            } else {
                Util.report("No file specified! Specify superlogger.file!");
            }
        } else if ("console".equals(output)) {
            out = new PrintWriter(System.out);
        }

        if (out == null) {
            out = new PrintWriter(System.out);
            Util.report("Using default output!");
        }
        return out;
    }

    private String initFormat(Properties conf) {
        String format = null;

        if (conf.containsKey("superlogger.format")) {
            format = conf.getProperty("superlogger.format");
        }

        if (format == null) {
            format = "%d [%n] [%l] %m";
            Util.report("Using default pattern: " + format);
        }
        return format;
    }


    public Logger getLogger(String name) {
        Logger simpleLogger = loggerMap.get(name);
        if (simpleLogger != null) {
            return simpleLogger;
        } else {
            Logger newInstance = new SuperLogger(format, writer, name, threshold);
            Logger oldInstance = loggerMap.putIfAbsent(name, newInstance);
            return oldInstance == null ? newInstance : oldInstance;
        }
    }

}
